class UploadsController < ApplicationController
  before_filter :get_project
  before_filter :get_class
  before_filter :get_group
  before_filter :only_members,
                :except => [:show, :index, :edit, :update]
  before_filter :is_teacher_or_member,
                :only => [:show, :index, :edit, :update]
  before_filter :get_upload

  # Shows uploads list
  #
  def index
    if @logged_user.is_teacher? # Teachers should see only final uploads
      @uploads = @group.uploads.find( :all,
                                      :conditions => {:final => 1},
                                      :order => "deadlines.end, uploads.title",
                                      :include => [:deadline])
    else
      @uploads = @group.uploads.find( :all,
                                      :order => "deadlines.end, uploads.title",
                                      :include => [:deadline])
    end

    respond_to do |wants|
      wants.html
      wants.xml   { render :xml => @uploads.to_xml }
    end
  end

  # Shows a single upload
  #
  def show
    respond_to do |wants|
      wants.html
      wants.xml { render :xml => @upload.to_xml }
    end
  end

  # Shows form to edit a upload. Only for GET requests.
  #
  def edit
    render :action => "notes" if @logged_user.is_teacher?
  end

  # Updates upload
  #
  def update
    params[:upload] ||= {}
    if @logged_user.is_teacher? # Only notes should be updated
      old_notes = @upload.notes
      result = @upload.update_attribute(:notes, params[:upload][:notes])
      SimpleMailer.deliver_new_note(@group, @group.users, @upload, @teaching, request.host_with_port) if old_notes != @upload.notes
    else
      was_final = @upload.final?
      result = @upload.update_attributes(params[:upload])
      SimpleMailer.deliver_new_file(@group, @logged_user, @upload, @teaching, request.host_with_port) if result && !was_final && @upload.final? # File was marked as final
    end
    
    if result
      respond_to do |wants|
        wants.html  { redirect_to upload_url(@project, @teaching, @group, @upload) }
        wants.js
        wants.xml   { head :ok }
      end
    else
      respond_to do |wants|
        wants.html do
          flash.now[:error] = 'Unable to save upload'
          unless @logged_user.is_teacher?
            render :action => "edit"
          else
            render :action => "notes"
          end
        end
        wants.js    { render :nothing => true, :status => 500 }
        wants.xml   { render :xml => @upload.errors.to_xml }
      end
    end
  end

  # Shows form to create a new upload. Only for GET requests.
  #
  def new
    @upload = Upload.new
  end

  # Creates new upload
  #
  def create
    params[:upload] ||= {}
   
    # If no title provided, use file name
    if params[:upload][:title].empty?
      params[:upload][:title] = ((params[:upload][:file] && !params[:upload][:file].is_a?(String)) ? Upload.get_base_name(params[:upload][:file].original_filename) : '')
    end
    @upload = @group.uploads.build(params[:upload])
    @upload.user = @logged_user
    # Create temp file
    file = params[:upload][:file]
    if(file && !file.is_a?(String) && file.length > 0 && file.length < AppConfig.max_file_size) # Exists, is not a string and is not empty
      @upload.file_name = Upload.get_base_name(file.original_filename)
      temp_file = Upload.generate_filename(Upload.get_base_name(file.original_filename), true, "#{File.expand_path(RAILS_ROOT)}/tmp/original_")
      
      if file.is_a?(StringIO) # Small files are not saved in temp files by Rails
        f = File.new(temp_file, "w") # Save file
        if f.write(file.read)
          f.close
        else # Unable to write data
          f.close
          @upload.errors.add(:file_name, 'unable to upload file')
          respond_to do |wants|
            wants.html do
              flash.now[:error] = "Unable to upload file"
              render :action => :new
            end
            wants.xml  { render :xml => @upload.errors.to_xml, :status => 500 }
          end
          return
        end
      end

      if(file.is_a?(StringIO) || FileUtils.mv(file.local_path, temp_file)) # Move only if it's a temp file
        if((@upload.file = temp_file) && @upload.save) # If it's nil photo wasn't saved
          respond_to do |wants|
            wants.html  { redirect_to upload_url(@project, @teaching, @group, @upload) }
            wants.xml   { head :created, :location => upload_url(@project, @teaching, @group, @upload) }
          end
        else
          respond_to do |wants|
            wants.html do
              flash.now[:error] = 'Unable to create upload'
              render :action => "new"
            end
            wants.js    { render :nothing => true, :status => 500 }
            wants.xml   { render :xml => @upload.errors.to_xml }
          end
        end
      else
        f.close
        logger.error("UploadsController: unable to write to #{temp_file}")
        @upload.errors.add(:file_name, 'unable to save file')
        respond_to do |wants|
          wants.html do
            flash.now[:error] = "Unable to upload file"
            render :action => :new
          end
          wants.xml  { render :xml => @upload.errors.to_xml, :status => 500 }
        end
      end
    else
      @upload.errors.add(:file_name, 'no file was given')
      respond_to do |wants|
        wants.html do
          flash.now[:error] = "Unable to upload file"
          render :action => :new
        end
        wants.xml  { render :xml => @upload.errors.to_xml, :status => 500 }
      end
    end
  end

  # Deletes upload
  #
  def destroy
    @upload.destroy

    respond_to do |wants|
      wants.html do
        flash[:note] = 'File deleted'
        redirect_to uploads_url(@project, @teaching, @group)
      end
      wants.js  { head :ok }
      wants.xml { head :ok }
    end
  end
private
  # Retrieves @group
  #
  def get_group
    @group = @teaching.groups.find(params[:group_id])
    raise if @group.nil?
    return true
  rescue
    respond_to do |wants|
      wants.html { render :text => "The group you're looking for doesn't exist!", :layout => true, :status => 404 }
      wants.js   { render :nothing => true, :status => 404 }
      wants.xml  { head :not_found }
    end
    return false
  end
  
  # If params[:id] is set, retrieves @upload
  #
  def get_upload
    unless params[:id].nil? || params[:id].blank?
      unless @logged_user.is_teacher?
        @upload = @group.uploads.find(params[:id])
      else # Teachers should only see uploads marked as final
        @upload = @group.uploads.find_by_id_and_final(params[:id], 1)
      end
      raise if @upload.nil?
    end
    return true
  rescue
    respond_to do |wants|
      wants.html { render :text => "The upload you're looking for doesn't exist!", :layout => true, :status => 404 }
      wants.js   { render :nothing => true, :status => 404 }
      wants.xml  { head :not_found }
    end
    return false
  end
end
